#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<assert.h>

//int main()
//{
//    close(1);//这里的fd分配规则是：最小的，没有被占用的文件描述符。
//    int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
//    if (fd < 0)
//    {
//        perror("open");
//        return 1;
//    }
//    
//    //都应该是往显示器打印的！(标准输出)
//    //但是下面的都写入到了log.txt，这叫输出重定向
//    printf("fd: %d\n", fd);// stdout -> FILE(fileno=1)->log.txt
//    printf("fd: %d\n", fd);
//    printf("fd: %d\n", fd);
//    printf("fd: %d\n", fd);
//    fprintf(stdout, "hello fprintf!\n");
//    const char* s = "hello wwirte\n";
//    fwrite(s, strlen(s), 1, stdout);
//
//    //////////////////////////////////////////////////////////////////////////
//    fflush(stdout);
//    close(fd);
//    return 0;
//}


//int main()
//{
//    //close(1);
//    //int fd = open("log.txt", O_WRONLY | O_TRUNC | O_CREAT);
//    int fd = open("log.txt", O_WRONLY | O_APPEND | O_CREAT);
//    if (fd < 0)
//    {
//        perror("open");
//        return 1;
//    }
//    fprintf(stdout, "you can see me, success\n");
//
//
//   // printf("fd: %d\n",fd);
//
//   // char buffer[64];
//   // fgets(buffer, sizeof buffer, stdin);
//
//   // printf("%s\n", buffer);
//
//
//    return 0;
//}

//dup重定向
//int main(int argc, char* argv[])
//{
//    if (argc != 2)
//    {
//        return 2;
//    }
//    int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
//    //int fd = open("log.txt", O_WRONLY | O_APPEND | O_CREAT);
//    if(fd < 0)
//    {
//        perror("open");
//        return 1;
//    }
//    dup2(fd, 1);//重定向
//    fprintf(stdout, "%s\n", argv[1]);// stdout -> 1 -> 显示器
//    close(fd);
//
//    return 0;
//}

////缓冲区在哪呢？
//int main()
//{
//    //C语言提供的
//    printf("hello printf\n");
//    fprintf(stdout, "hello fprintf\n");
//    const char* s = "hello fputs\n";
//    fputs(s, stdout);
//    
//    //OS提供的接口
//    const char* ss = "hello write\n";
//    write(1, ss, strlen(ss));
//    //在fork之前,强制刷新一下，向文件中重定向，就只有4条输出信息
//    fflush(stdout);
//
//    fork();//创建子进程
//
//    return 0;
//}
//

//简单了封装一下文件描述符
#define NUM 1024

struct MyFILE_{
    int fd;
    char buffer[1024];
    int end;//当前缓冲区的结尾
};

typedef struct MyFILE_ MyFILE;

MyFILE *fopen_(const char* pathname, const char* mode)
{
    assert(pathname);
    assert(mode);

    MyFILE* fp = NULL;

    if(strcmp(mode, "r") == 0)
    {
        
    }
    else if (strcmp(mode, "r+") == 0)
    {

    }
    else if (strcmp(mode, "w") == 0)
    {
        int fd = open(pathname, O_WRONLY | O_TRUNC | O_CREAT, 0666);
        if (fd >= 0)
        {
            fp = (MyFILE*)malloc(sizeof (MyFILE));
            memset(fp, 0, sizeof(MyFILE));
            fp->fd = fd;
        }
    }
    else if (strcmp(mode, "w+") == 0)
    {

    }
    else if (strcmp(mode, "a") == 0)
    {

    }
    else if (strcmp(mode, "a+") == 0)
    {

    }
    else 
    {
        //什么都不做
    }
    return fp;
}

//C标准库的实现！
void fputs_(const char* message, MyFILE* fp)
{
    assert(message);
    assert(fp);

    strcpy(fp->buffer+fp->end, message);
    fp->end += strlen(message);

    //for debug
    printf("%s\n", fp->buffer);

    //暂时没有刷新, 刷新策略是谁来执行的？用户通过执行c标准库中的代码逻辑，来完成刷新
    //效率提高体现在哪里？？？因为C提供了缓冲区，那么通过策略，减少了IO的执行次数(不是数据)
    if(fp->fd == 0)
    {
        //标准输入
    }
    else if (fp->fd == 1)
    {
        //标准输出
        if(fp->buffer[fp->end - 1] == '\n')
        {
            //fprintf(stderr, "fflush: %s", fp->buffer);//2
            write(fp->fd, fp->buffer, fp->end);
            fp->end = 0;
        }
    }
    else if (fp->fd == 2)
    {
        //标准错误
    }
    else 
    {

    }
}

void fflush_(MyFILE* fp)
{
    assert(fp);
    if(fp->end != 0)
    {
        //暂且认为刷新了 -- 其实是把数据写进了内核
        write(fp->fd, fp->buffer, fp->end);
        syncfs(fp->fd);//将数据写入到磁盘
        fp->end = 0;
    }
}

void fclose_(MyFILE* fp)
{                                                                                                                                                 
     assert(fp);
     fflush_(fp);
     close(fp->fd);
     free(fp);
 }

int main()
{
    //close(1);
    MyFILE *fp = fopen_("./log.txt", "w");    
    if(fp == NULL)
    {
        printf("open file error");
        return 1;
    }
    
    fputs_("one: hello world", fp);

    fork();


   // sleep(1);
   // fputs_("two: hello world", fp);
   // sleep(1);
   // fputs_("three: hello world", fp);
   // sleep(1);
   // fputs_("four: hello world\n", fp);

    fclose_(fp);
}
